package com.xxjh.brs.ftp.factory;

import com.xxjh.brs.ftp.common.api.enums.ResponseStatus;
import com.xxjh.brs.ftp.common.exceptions.ConditionException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @author CHENCHEN
 * @title FTP客户端工厂
 * @company 新兴际华科技（天津）有限公司
 * @create 2024-07-03 19:21
 */
@Component
public class FtpClientFactory {

    // 最大连接数
    private static final int MaxTotal = 50;
    // 最小空闲连接数
    private static final int MinIdle = 200;
    // 最大等待时间
    private static final int MaxWaitMillis = 10000;

    @Autowired
    private FtpProperties ftpProperties;

    @Bean(name = "ftpClientPoolPull")
    public ObjectPool<FTPClient> ftpClientPoolPull() {
        return getObjectPool(ftpProperties.getPullServer());
    }

    @Bean(name = "ftpClientPoolPush")
    public ObjectPool<FTPClient> ftpClientPoolPush() {
        return getObjectPool(ftpProperties.getPushServer());
    }

    private ObjectPool<FTPClient> getObjectPool(FtpProperties.FtpServer server){
        GenericObjectPoolConfig<FTPClient> config = new GenericObjectPoolConfig<>();
        config.setMaxTotal(MaxTotal);
        config.setMinIdle(MinIdle);
        config.setMaxWaitMillis(MaxWaitMillis); //TODO: ！【谨慎开启】！
        return new GenericObjectPool<>(new FtpClientFactory.ServerConnectionFactory(server), config);
    }


    // FTPClient的连接工厂类
    private static class ServerConnectionFactory extends BasePooledObjectFactory<FTPClient> {

        private final FtpProperties.FtpServer ftpServerConfig;

        public ServerConnectionFactory(FtpProperties.FtpServer serverConfig) {
            this.ftpServerConfig = serverConfig;
        }

        @Override
        public FTPClient create() throws Exception {
            FTPClient client = new FTPClient();
            client.connect(ftpServerConfig.getHost(), ftpServerConfig.getPort());
            if (!client.login(ftpServerConfig.getUsername(), ftpServerConfig.getPassword())) {
                throw new ConditionException(ResponseStatus.FTP_CONNECT_EXCEPTION);
            }
            client.enterLocalPassiveMode(); // 设置被动模式
            client.setFileType(FTP.BINARY_FILE_TYPE); // 设置传输文件类型为二进制
            client.changeWorkingDirectory(ftpServerConfig.getRoot());
            return client;
        }

        @Override
        public PooledObject<FTPClient> wrap(FTPClient client) {
            return new DefaultPooledObject<>(client); // 将FTPClient包装成PooledObject以便于池管理
        }

        @Override
        public boolean validateObject(PooledObject<FTPClient> pooledObject) {
            FTPClient client = pooledObject.getObject();
            try {
                return client.sendNoOp(); // 发送NOOP命令检查连接是否有效
            } catch (IOException e) {
                return false; // 发生异常说明连接可能已失效
            }
        }

        @Override
        public void destroyObject(PooledObject<FTPClient> pooledObject) throws Exception {
            FTPClient client = pooledObject.getObject();
            try {
                if (client.isConnected()) {
                    client.logout();
                }
            } finally {
                client.disconnect();
            }
        }

        @Override
        public void activateObject(PooledObject<FTPClient> pooledObject) throws Exception {
            // 在对象被激活时执行的操作
        }

        @Override
        public void passivateObject(PooledObject<FTPClient> pooledObject) throws Exception {
            // 在对象被归还到池中之前执行的操作
        }
    }
}
